package org.codehaus.activemq.util;

import EDU.oswego.cs.dl.util.concurrent.Executor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class AsyncProxy implements InvocationHandler {
	private Object realObject;
	private Executor executor;
	private Log log;

	public static Object createProxy(Class interfaceType, Object realObject, Executor executor) {
		return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { interfaceType },
				new AsyncProxy(realObject, executor));
	}

	public AsyncProxy(Object realObject, Executor executor) {
		this(realObject, executor, LogFactory.getLog(AsyncProxy.class));
	}

	public AsyncProxy(Object realObject, Executor executor, Log log) {
		this.realObject = realObject;
		this.executor = executor;
		this.log = log;
	}

	public AsyncProxy(Executor executor, Log log) {
		this.executor = executor;
		this.log = log;
	}

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if (method.getReturnType() == Void.TYPE) {
			this.executor.execute(new Runnable() {
				private final Method val$method=method;
				private final Object[] val$args=args;

				public void run() {
					AsyncProxy.this.doAsyncMethodInvoke(this.val$method, this.val$args);
				}
			});
			return null;
		}

		return method.invoke(this.realObject, args);
	}

	protected void doAsyncMethodInvoke(Method method, Object[] args) {
		try {
			method.invoke(this.realObject, args);
		} catch (Throwable e) {
			this.log.warn("Caught exception: " + e, e);
		}
	}
}